import 'dart:async';
import 'package:flutter/material.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:qgchat/common/class/eventBus/index.dart';
import 'package:qgchat/common/class/websocket/settings.dart';
import 'package:qgchat/common/global/global.dart';
import 'package:qgchat/http/models/chatModel.dart';
import 'package:qgchat/http/models/giftModel.dart';
import 'package:qgchat/http/models/socketModel.dart';
import 'package:qgchat/http/models/userInfoModel.dart';
import 'package:qgchat/http/models/wsAllGiftModel.dart';
import 'package:qgchat/states/states_model/index.dart';
import 'package:qgchat/states/states_model/socket.dart';
import 'package:qgchat/widgets/gitfToast.dart';
import 'package:web_socket_channel/io.dart';
import 'package:qgchat/common/class/audio/index.dart';

/// 全局websocket模块封装
class WebSocket {
  /// websocket
  IOWebSocketChannel channel;

  /// stearm
  final ValueNotifier<Stream> streamNotifier = ValueNotifier<Stream>(null);

  /// 计时器
  Timer _timer;

  /// 用户信息
  UserInfoModel _userInfo;

  /// 不打印的类型
  List _disablePrint = ['heartbeat'];

  /// 当前ws是否运行中
  bool isActive = false;

  // 函数节流
  Timer timer;
  Duration durationTime = Duration(seconds: 5);

  // 当前未响应心跳次数
  int stopHeartbeat = 0;

  // 多少次没有响应心跳就直接重连
  int stopHeartbeatReconnt = 2;

  WebSocket(UserInfoModel userInfo) {
    _userInfo = userInfo;

    // 启动socket
    _start();
  }

  /// 启动socket
  void _start() async {
    // 关闭旧socket
    if (channel != null && !isActive) {
      dispose();
    }

    // 初始化socket
    String connectUrl = '$CONNECT_ADDRESS?token=${_userInfo.memberToken}';
    channel = IOWebSocketChannel.connect(connectUrl);
    final asStream = channel.stream.asBroadcastStream();
    Global.socketNot.value = asStream;
    streamNotifier.value = asStream;
    streamNotifier.value.listen(_onData, onError: _onError, onDone: _onDone);

    // 改变socket状态
    isActive = true;

    // 心动的开始
    _heartbeat();
  }

  /// 监听socket消息
  void _onData(event) {
    SocketModel data = SocketModel.fromJson(deJson(event));

    if (!_disablePrint.contains(data.datatype)) {
      print('心跳包....');
      print(
        '${_userInfo.memberType == 1 ? '主播' : '用户'}[ID：${_userInfo.id}]-${_userInfo.memberNickname} 接收到[${data.datatype}]：${data.data} 消息：${data.msg}',
      );
    }

    switch (data.datatype) {
      case 'heartbeat': // 心跳
        stopHeartbeat--;
        break;
      case 'message': // 私信
        _listenMessage(data);
        break;
      case 'text': // 视频中文字聊天
        _listenVideoMessage(data);
        break;
      case 'gift': // 礼物
        _listenGift(data);
        break;
      case 'invitation': // 监听视频通话邀请
        // _listenInviteVideo(data);
        break;
      case 'invtokening': // 监听对方接听通话，并返回邀请id
        _listenInvtokening(data);
        break;
      case 'uninvtoken': // 拒绝视频通话 有坑,已废弃 用stoptalk代替
        break;
      case 'stoptalk': // 挂断视频通话
        _listenStoptalk(data);
        break;
      case 'allgift': // 全局广播-礼物
        _listenGlobalGift(data);
        break;
      case 'allmoney': // 全局广播-充值
        break;
      case 'allred': // 全局广播-红包
        break;
      case 'violation': // 鉴黄师中断视频
        break;
      case 'warning': // 鉴黄师警告
        break;
      case 'error': //错误
        _handleError(data);
        break;
      default:
    }
  }

  /// 监听socket错误
  void _onError(e) {
    isActive = false;
    reconnect();
    print('socket错误：$e');
  }

  /// 监听socket结束
  void _onDone() {
    print("结束");
    isActive = false;
    if (cache.getString('token') != null) {
      print("socket结束 重连");
      _start();
    }
  }

  /// 发送消息
  void _send(Map obj) {
    if (channel == null) {
      return;
    }

    channel.sink.add(toJson(obj));
  }

  /// 心跳包
  void _heartbeat() {
    _timer = Timer.periodic(HEARTBEAT, (timer) {
      if (stopHeartbeatReconnt > stopHeartbeat) {
        stopHeartbeat++;
        _send({'datatype': 'heartbeat'});
      } else {
        if (cache.getString('token') != null) {
          print("心跳假死 重连 $stopHeartbeatReconnt $stopHeartbeat");
          reconnect();
        }
      }
    });
  }

  /// 处理后台错误
  void _handleError(SocketModel data) {
    switch (data.status) {
      case -2:
        showToast(data.msg);
        state(Global.context, "user").logout();
        dispose();
        break;
    }
  }

  /// 监听私信
  void _listenMessage(SocketModel data) {
    UserState userState = (state(Global.context, 'user') as UserState);
    SocketState socketState = (state(Global.context, 'socket') as SocketState);
    socketState.addMessage(
      data.data['token'],
      userName: data.data['name'],
      userHead: data.data['head'],
      msg: Msglist(
        token: data.data['token'],
        userToken: userState.info.memberToken,
        message: data.data['msg'],
        type: 1,
        userName: data.data['name'],
        userHead: data.data['head'],
        isread: 0,
        createtime: (DateTime.now().millisecondsSinceEpoch / 1000).floor(),
      ),
    );

    bus.emit("listenMessage", data.data);

    Global.audio.play(Audios.Message);
  }

  /// 监听视频中的文字聊天
  void _listenVideoMessage(SocketModel data) {
    bus.emit("listenVideoMessage", data.data);
  }

  /// 监听视频♂邀请
  void _listenInviteVideo(SocketModel data) async {
    final permissions = await PermissionHandler().requestPermissions([
      PermissionGroup.camera,
      PermissionGroup.microphone,
    ]);
    final camera = permissions[PermissionGroup.camera] == PermissionStatus.granted;
    final microphone = permissions[PermissionGroup.microphone] == PermissionStatus.granted;
    if (!camera || !microphone) {
      PermissionHandler().openAppSettings();
      return;
    }
    
    /// socket状态
    SocketState socketState = state(Global.context, 'socket');
    // 跳转等待接通页面
    if (!socketState.onTheCall) {
      // 切换通话状态 - 通话中
      socketState.toggleCallState(true);

      Global.noCtxRoute.navigateTo("/answerPhone", arguments: {
        "targetInv": data.data['inv'],
        "targetId": data.data['id'],
        "targetName": data.data['nickname'],
        "targetHead": data.data['head'],
        "targetToken": data.data['token'],
      });
    }
  }

  /// 监听挂断视频通话
  void _listenStoptalk(SocketModel data) {
    showToast("${data.msg}");

    /// socket状态
    SocketState socketState = state(Global.context, 'socket');
    // 设置通话状态为未通话
    socketState.toggleCallState(false);

    bus.emit("wsStopTalk");
    print("------------------");
    print("ws对方关电话");
    print("------------------");
    if (listenStoptalk != null) {
      listenStoptalk();
    }
  }

  /// 监听对方接听通话，并返回邀请id
  void _listenInvtokening(SocketModel data) {
    int inv = data.data['inv'];
    if (listenInvtokening != null) {
      listenInvtokening(inv);
    }
  }

  /// 监听收到礼物
  void _listenGift(SocketModel data) {
    if (_userInfo.memberType == 1) {
      bus.emit("gift", GiftModel.fromJson(data.data));
    }
  }

  /// 监听全局礼物
  void _listenGlobalGift(SocketModel data) {
    GiftToast.show(WsAllGiftModel.fromJson(data.data));
  }

  // ##########  暴露回调方法  ##############

  void disposeCallBack() {
    listenInvtokening = null;
    listenStoptalk = null;
  }

  /// 对方返回邀请id回调
  Function(int inv) listenInvtokening;

  /// 对方挂断电话回调
  Function listenStoptalk;

  // ##########  暴露的api (功能区)  ##############

  /// 发送私信
  void sendMessage(String targetToken, String text) {
    _send({'datatype': 'message', 'token': targetToken, 'text': text});
  }

  /// 发送视频中私信
  void sendVideoMessage(String targetToken, String text) {
    _send({'datatype': 'text', 'token': targetToken, 'text': text});
  }

  /// 发起视频♂邀请
  void inviteVideo(String targetToken) {
    _send({'datatype': 'invitation', 'token': targetToken});
  }

  /// 接受视频邀请，发送邀请id给对方
  void sendInvtokening(int inv) {
    _send({'datatype': 'invtokening', 'id': inv});
  }

  /// 拒绝视频♂邀请
  void refuseVideo(int inv) {
    _send({'datatype': 'uninvtoken', 'id': inv});
  }

  /// 停止视频邀请
  void stopinv(String token) {
    _send({'datatype': 'stopinv', 'token': token});
  }

  /// 挂断视频
  void stoptalk(String targetToken, {String msg}) {
    _send({
      'datatype': 'stoptalk',
      'token': targetToken,
      'msg': msg ?? '对方拒绝你的通话请求',
    });
  }

  /// 重连socket
  void reconnect() {
    if (isActive) {
      print("重连");
      dispose();
    }
  }

  /// 销毁WebSocket
  void dispose() {
    channel?.sink?.close();
    channel = null;
    _timer?.cancel();
  }
}
